package android.mcsmtms.fragment;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Document;

import android.mcsmtms.domain.MobileUserReport;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Color;
import android.mcsmtms.R;
import android.mcsmtms.constant.GlobalConstants;
import android.mcsmtms.constant.GlobalConstants.SituationTypes;
import android.mcsmtms.constant.GlobalConstants.TrafficConditionTypes;
import android.mcsmtms.constant.GlobalConstants.UserTypes;
import android.mcsmtms.domain.Place;
import android.mcsmtms.domain.SituationReport;
import android.mcsmtms.domain.SituationSegment;
import android.mcsmtms.domain.User;
import android.mcsmtms.manager.GMapV2Direction;
import android.mcsmtms.manager.PlacesManager;
import android.mcsmtms.rest.RestClient;
import android.mcsmtms.util.JsonHelper;
import android.mcsmtms.util.Utilities;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.MarkerOptionsCreator;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.gson.reflect.TypeToken;

public class HazardMapFragment extends Fragment {
	private static View view;
	private User loggedUser;
	private GoogleMap hazardMap;
	private List<Marker> hospitalMarkerList;
	private List<Marker> policeMarkerList;
	private List<Marker> evacCenterMarkerList;
	private List<Marker> userReportMarkerList;
	
	private final String POI_HOSPITAL = "hospital";
	private final String POI_POLICE = "police";
	private final String POI_EVAC_CENTER = "school";
	private final String POI_USER_REPORT = "user_report";
	
	private HashMap<String, String> markerDetailsMap = new HashMap<String, String>();
	
	private Map<Integer, Boolean> filterStateMap = new HashMap<Integer, Boolean>();
	private String selectedDirection = GlobalConstants.Direction.A_TO_B.getCode();
	
//	private Handler refreshHazardMapHandler = new Handler() {
//		public void handleMessage(Message msg) {
//			Toast.makeText(getActivity(), "Error in downloading hazard hazardMap!", Toast.LENGTH_SHORT).show();
//			renderHazardMap();
//		}
//	};
	
	 @Override
	    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
	        Bundle savedInstanceState) {
		 
		 	if (view != null) {
	            ViewGroup parent = (ViewGroup) view.getParent();
	            if (parent != null)
	                parent.removeView(view);
	        }
	        try {
	        	view = inflater.inflate(R.layout.fragment_hazard_map, container, false);
	        } catch (InflateException e) {
	            /* hazardMap is already there, just return view as it is */
	        }
	        setHasOptionsMenu(true);
	        return view;
	    }
	 
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		
		if (savedInstanceState != null) {
            return;
        }
		
		FragmentManager fragmentManager = getFragmentManager();
	 	Fragment mapFragment = fragmentManager.findFragmentById(R.id.map_hazard);
	 	hazardMap = ((SupportMapFragment)mapFragment).getMap();
	 	
	 	hazardMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(14.650399, 121.102417), 14));
	 	
	 	loggedUser = Utilities.getLoggedUser(this.getActivity());
	 	
	 	renderHazardMap();
	}
	
	public void renderHazardMap() {
		RenderHazardMapTask renderHazardMapTask = new RenderHazardMapTask(false, selectedDirection);
	 	renderHazardMapTask.execute();
	}
	
	public void refreshHazardMap() {
		if(hospitalMarkerList != null) hospitalMarkerList.clear();
		if(policeMarkerList != null) policeMarkerList.clear();
		if(evacCenterMarkerList != null) evacCenterMarkerList.clear();
		if(userReportMarkerList != null) userReportMarkerList.clear();
		if(markerDetailsMap != null) markerDetailsMap.clear();
		
//		private List<Marker> hospitalMarkerList;
//		private List<Marker> policeMarkerList;
//		private List<Marker> evacCenterMarkerList;
//		private List<Marker> userReportMarkerList;
			
		RenderHazardMapTask renderHazardMapTask = new RenderHazardMapTask(true, selectedDirection);
	 	renderHazardMapTask.execute();
	}
	
	private void displayPlaceOfInterest(MenuItem menuItem, String poi) {
		boolean isVisible = false;
		if (menuItem.isChecked()) {
			menuItem.setChecked(false);
		} else {
			menuItem.setChecked(true);
			isVisible = true;
		}
		filterStateMap.put(menuItem.getItemId(), isVisible);
		
		List<Marker> markerList = null;
		if(poi.equals(POI_HOSPITAL)) {
			markerList = hospitalMarkerList;
		} else if(poi.equals(POI_POLICE)) {
			markerList = policeMarkerList;
		} else if(poi.equals(POI_EVAC_CENTER)) {
			markerList = evacCenterMarkerList;
		} else if(poi.equals(POI_USER_REPORT)) {
			markerList = userReportMarkerList;
		}
		
		if(markerList != null && markerList.size() > 0) {
			displayPOIMarker(markerList, isVisible);
		} else {
			if(isVisible && !poi.equals(POI_USER_REPORT)) {
				GetPlacesTask getPlacesTask = new GetPlacesTask(this.getActivity(), poi);
				getPlacesTask.execute((Void) null);
			}
		}
	}
	
	private void displayPOIMarker(List<Marker> markerList, boolean isVisible) {
		if(markerList != null && markerList.size() > 0) {
			for(Marker marker : markerList) {
				marker.setVisible(isVisible);
			}
		}
	}
	
	private void refreshPOIMarker(List<Marker> markerList, String poi) {
		markerList.clear();
		GetPlacesTask getPlacesTask = new GetPlacesTask(this.getActivity(), poi);
		getPlacesTask.execute((Void) null);
	}
	
	
	private void refreshPOIMarkers() {
		
		for(Integer menuItemId : filterStateMap.keySet()) {
			switch (menuItemId) {
				case R.id.hospitals:
					if(filterStateMap.get(menuItemId))
						refreshPOIMarker(hospitalMarkerList, POI_HOSPITAL);
					
					break;
				case R.id.police_stations:
					if(filterStateMap.get(menuItemId))
						refreshPOIMarker(policeMarkerList, POI_POLICE);
					
					break;
				case R.id.evac_centers:
					if(filterStateMap.get(menuItemId))
						refreshPOIMarker(evacCenterMarkerList, POI_EVAC_CENTER);
					
					break;
				case R.id.user_reports:
					if(filterStateMap.get(menuItemId))
						displayPOIMarker(userReportMarkerList, filterStateMap.get(menuItemId));
					
					break;
				default:

			}
		}
		
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem menuItem) {
		switch (menuItem.getItemId()) {
			case R.id.hospitals:
				displayPlaceOfInterest(menuItem, POI_HOSPITAL);
				return true;
			case R.id.police_stations:
				displayPlaceOfInterest(menuItem, POI_POLICE);
				return true;
			case R.id.evac_centers:
				displayPlaceOfInterest(menuItem, POI_EVAC_CENTER);
				return true;
			case R.id.user_reports:
				displayPlaceOfInterest(menuItem, POI_USER_REPORT);
				return true;
			case R.id.a_to_b:
//				if(menuItem.isChecked()) {
//					menuItem.setChecked(false);
//				} else { 
				menuItem.setChecked(true);
				selectedDirection = GlobalConstants.Direction.A_TO_B.getCode();
				refreshHazardMap();
				//}
				
				return true;
			case R.id.b_to_a:
//				if(menuItem.isChecked()) {
//					menuItem.setChecked(false);
//				} else {
				menuItem.setChecked(true);
				selectedDirection = GlobalConstants.Direction.B_TO_A.getCode();
				refreshHazardMap();
				//}
				
				return true;	
			default:
				return super.onOptionsItemSelected(menuItem);
		}
	}
	
	public class RenderHazardMapTask extends AsyncTask<Void, Void, Map<String, Object>> {
		private static final String HAZARD_MAP_REPORTS_REST_URL = GlobalConstants.RestUrls.HAZARD_MAP_URL;
		private static final String MOBILE_REPORTS_REST_URL = GlobalConstants.RestUrls.MOBILE_USER_REPORTS_URL;
		private ProgressDialog dialog;
		private boolean isRefresh = false;
		private String direction;
		
		public RenderHazardMapTask(boolean isRefreshOperation, String direction) {
			isRefresh = isRefreshOperation;
			this.direction = direction;
		}
		
		@SuppressWarnings("unchecked")
		@Override
		protected Map<String, Object> doInBackground(Void... params) {
			List<SituationReport> hazardMapList = null;
			List<MobileUserReport> mobileUserReportList = null;
			Map<String, Object> hazardMapDetails = new HashMap<String, Object>();
			
			try {
				// Simulate network access.
				//Thread.sleep(2000);
				RestClient client = new RestClient(HAZARD_MAP_REPORTS_REST_URL + direction, loggedUser.getUserName(), loggedUser.getPassword());
				
			    client.execute(RestClient.RequestMethod.GET);
				
				String hazardMapDetailsResponse = client.getResponse();
				hazardMapList = (List<SituationReport>) JsonHelper.getObject(hazardMapDetailsResponse, new TypeToken<List<SituationReport>>(){}.getType(), "hazardMapList");
				
				RestClient userReportsClient = new RestClient(MOBILE_REPORTS_REST_URL, loggedUser.getUserName(), loggedUser.getPassword());
				
				userReportsClient.execute(RestClient.RequestMethod.GET);
				
				String userReportsResponse = userReportsClient.getResponse();
				mobileUserReportList = (List<MobileUserReport>) JsonHelper.getObject(userReportsResponse, new TypeToken<List<MobileUserReport>>(){}.getType(), "mobileUserReportList");
				
				GMapV2Direction md = new GMapV2Direction();
				
				for(SituationReport situationReport : hazardMapList) {
					for(SituationSegment situationSegment : situationReport.getSituationSegmentList()) {
						LatLng fromPosition = new LatLng(situationSegment.getStartLat(), situationSegment.getStartLng());
						LatLng toPosition = new LatLng(situationSegment.getEndLat(), situationSegment.getEndLng());
						Document doc = md.getDocument(fromPosition, toPosition, GMapV2Direction.MODE_DRIVING);

						ArrayList<LatLng> directionPoint = md.getDirection(doc);
						
						int trafficColor = 0; 
						if(TrafficConditionTypes.LIGHT.getCode().equals(situationSegment.getTrafficCondition())) {
							trafficColor = Color.YELLOW;
						} else if(TrafficConditionTypes.NORMAL.getCode().equals(situationSegment.getTrafficCondition())) {
							trafficColor = Color.GREEN;
						} else if(TrafficConditionTypes.HEAVY.getCode().equals(situationSegment.getTrafficCondition())) {
							trafficColor = Color.RED;
						}
						
						PolylineOptions rectLine = new PolylineOptions().width(15).color(trafficColor);
						
						for(int i = 0 ; i < directionPoint.size() ; i++) {			
							rectLine.add(directionPoint.get(i));
						}
						
						situationSegment.setPolyLineOptions(rectLine);
					}
				}
				
				hazardMapDetails = new HashMap<String, Object>();
				hazardMapDetails.put("hazardMapList", hazardMapList);
				hazardMapDetails.put("mobileUserReportList", mobileUserReportList);
				
			} catch (Exception ex) {
				//Toast.makeText(getActivity(), "Error in rendering hazard hazardMap!", Toast.LENGTH_SHORT).show();
				Log.e("Hazard Map Download Error", "Error in downloading HazardMap details: " + Utilities.getErrorMessage(ex));
				return null;
			}
			
			return hazardMapDetails;
		}
		
		@SuppressWarnings("unchecked")
		@Override
		protected void onPostExecute(Map<String, Object> hazardMapDetails) {
			super.onPostExecute(hazardMapDetails);
			
			if (dialog.isShowing()) {
				dialog.dismiss();
			}
			
			if(hazardMapDetails == null) {
				//Utilities.showDefaultAlertDialog(getActivity(), "Error", "Error in downloading hazard map details. Tap refresh button to retry.");
				refreshHazardMap();
			} else {
				try {
					hazardMap.clear();
					List<SituationReport> hazardMapList = (List<SituationReport>) hazardMapDetails.get("hazardMapList");
					if(hazardMapList != null && hazardMapList.size() > 0) {
						for(SituationReport situationReport : hazardMapList) {
							for(SituationSegment situationSegment : situationReport.getSituationSegmentList()) {
								PolylineOptions polyLineOptions = situationSegment.getPolyLineOptions();
								//polyLineOptions.
								
								hazardMap.addPolyline(situationSegment.getPolyLineOptions());
								LatLng midPoint = new LatLng(situationSegment.getStartLat(), situationSegment.getStartLng());
								if(situationSegment.getPolyLineOptions().getPoints().size() > 0) {
									int midPointIdx = situationSegment.getPolyLineOptions().getPoints().size() / 2;
									
									midPoint = situationSegment.getPolyLineOptions().getPoints().get(midPointIdx);
								}
								
								int situationIcon = 0;
								
								if(SituationTypes.ACCIDENT.getCode().equals(situationSegment.getSituation())) {
									situationIcon = R.drawable.icon_accident;
								} else if(SituationTypes.ROAD_WORKS.getCode().equals(situationSegment.getSituation())) {
									situationIcon = R.drawable.icon_road_works;
								} else if(SituationTypes.BAD_WEATHER.getCode().equals(situationSegment.getSituation())) {
									situationIcon = R.drawable.icon_bad_weather;
								} else if(SituationTypes.BLOCKED.getCode().equals(situationSegment.getSituation())) {
									situationIcon = R.drawable.icon_road_closed;
								} else if(SituationTypes.FLOOD.getCode().equals(situationSegment.getSituation())) {
									situationIcon = R.drawable.icon_flood;
								}
								
								
								Marker marker = hazardMap.addMarker(new MarkerOptions()
			                     						.position(midPoint)
			                     						.title(situationSegment.getTrafficCondition())
			                     						//.snippet(Utilities.generateSegmentDetails(situationReport, situationSegment))
			                     						.icon(BitmapDescriptorFactory.fromResource(situationIcon)));

								markerDetailsMap.put(marker.getId(), Utilities.generateSegmentDetails(situationReport, situationSegment));
								//hazardMap.addMarker(new MarkerOptions().position(fromPosition).title("Start"));
								//hazardMap.addMarker(new MarkerOptions().position(toPosition).title("End"));
							}
						}
					} else {
						Toast.makeText(getActivity(), "No valid reports available", Toast.LENGTH_LONG).show();
					} 
					
					List<MobileUserReport> mobileUserReportList = (List<MobileUserReport>) hazardMapDetails.get("mobileUserReportList");
					
					if(mobileUserReportList != null && mobileUserReportList.size() > 0) {
						for(MobileUserReport userReport : mobileUserReportList) {
							LatLng userPosition = new LatLng(userReport.getLocationLat(), userReport.getLocationLng());
							if(userReportMarkerList == null)
								userReportMarkerList = new ArrayList<Marker>();
							
							if(isRefresh)
								userReportMarkerList.clear();
							
							BitmapDescriptor icon;
							if (UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.SCOUT ||  
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.BAYANAN_SCOUT ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.ESANTOS_SCOUT ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.JMOLINA_SCOUT ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.JPRIZAL_SCOUT ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.EROD_SCOUT ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.BAYANAN_MMDA ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.ESANTOS_MMDA ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.JMOLINA_MMDA ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.JPRIZAL_MMDA ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.EROD_MMDA ||
									UserTypes.valueOf(userReport.getUser().getUserType()) == UserTypes.MMDA) {
								icon = BitmapDescriptorFactory.fromResource(R.drawable.marker_scout);
							} else {
								icon = BitmapDescriptorFactory.fromResource(R.drawable.marker_car);
							}
							
							
							Marker userReportMarker = hazardMap.addMarker(new MarkerOptions()
														.position(userPosition)
														.title(userReport.getTrafficCondition())
														//.snippet(Utilities.generateMobileUserReportDetails(userReport))
														.icon(icon));
							userReportMarker.setVisible(false);
							
							markerDetailsMap.put(userReportMarker.getId(), Utilities.generateMobileUserReportDetails(userReport));
							
							userReportMarkerList.add(userReportMarker);
						}
					}
					
					if(isRefresh) {
						refreshPOIMarkers();
					}
						
				} catch (Exception ex) {
					ex.printStackTrace();
					Log.e("Hazard Map Error", "Error in rendering HazardMap: " + Utilities.getErrorMessage(ex));
					//Utilities.showDefaultAlertDialog(getActivity(), "Error", "Error in rendering hazard map details. Tap refresh button to retry.");
					refreshHazardMap();
				}
				
				hazardMap.setInfoWindowAdapter(new InfoWindowAdapter() {

			        @Override
			        public View getInfoWindow(Marker arg0) {
			            return null;
			        }

			        @Override
			        public View getInfoContents(Marker marker) {

			            View v = getActivity().getLayoutInflater().inflate(R.layout.infowindow, null);

			            TextView info= (TextView) v.findViewById(R.id.info);
			            info.setText(markerDetailsMap.get(marker.getId()));

			            return v;
			        }
			    });
			}
		}

		@Override
		protected void onCancelled() {
//			mAuthTask = null;
//			showProgress(false);
		}
		
		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			dialog = new ProgressDialog(getActivity());
			dialog.setCancelable(false);
			dialog.setMessage("Loading..");
			dialog.isIndeterminate();
			dialog.show();
		}
	}
	
//	private placeMarker() {
//		
//	}
	
	private class GetPlacesTask extends AsyncTask<Void, Void, List<Place>> {

		private ProgressDialog dialog;
		private Context context;
		private String places;

		public GetPlacesTask(Context context, String places) {
			this.context = context;
			this.places = places;
		}

		@Override
		protected List<Place> doInBackground(Void... params) {
			ApplicationInfo ai;
			String mapsApiKey = null;

			try {
				ai = context.getPackageManager().getApplicationInfo(
						context.getPackageName(),
						PackageManager.GET_META_DATA);
				Bundle bundle = ai.metaData;
				mapsApiKey = bundle
						.getString("com.google.android.maps.v2.API_KEY");
			} catch (NameNotFoundException e) {
				e.printStackTrace();
				Log.e("Error", "error in getting maps api key");
			}

			PlacesManager placesManager = new PlacesManager(mapsApiKey);
			ArrayList<Place> placeList = placesManager.findPlaces(14.650399, 121.102417, places);

			for (int i = 0; i < placeList.size(); i++) {
				Place placeDetail = placeList.get(i);
				Log.i("Places", "places : " + placeDetail.getName());
			}
			return placeList;
		}

		@Override
		protected void onPostExecute(List<Place> placeList) {
			super.onPostExecute(placeList);

			if (dialog.isShowing()) {
				dialog.dismiss();
			}
			
			for(Place place : placeList) {
				LatLng placeLatLng = new LatLng(place.getLatitude(), place.getLongitude());
				MarkerOptions poiMarkerOptions = new MarkerOptions().position(placeLatLng).title(place.getName());
				
				if(places.equals(POI_HOSPITAL)) {
					poiMarkerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_hospital));
					Marker marker = hazardMap.addMarker(poiMarkerOptions);
					if(hospitalMarkerList == null)
						hospitalMarkerList = new ArrayList<Marker>();
					markerDetailsMap.put(marker.getId(), place.getName());
					hospitalMarkerList.add(marker);
				} if(places.equals(POI_POLICE)) {
					poiMarkerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_police));
					Marker marker = hazardMap.addMarker(poiMarkerOptions);
					if(policeMarkerList == null)
						policeMarkerList = new ArrayList<Marker>();
					markerDetailsMap.put(marker.getId(), place.getName());
					policeMarkerList.add(marker);
				} if(places.equals(POI_EVAC_CENTER)) {
					poiMarkerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_evac));
					Marker marker = hazardMap.addMarker(poiMarkerOptions);
					if(evacCenterMarkerList == null)
						evacCenterMarkerList = new ArrayList<Marker>();
					markerDetailsMap.put(marker.getId(), place.getName());
					evacCenterMarkerList.add(marker);
				} 
			}
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			dialog = new ProgressDialog(context);
			dialog.setCancelable(false);
			dialog.setMessage("Loading..");
			dialog.isIndeterminate();
			dialog.show();
		}
	}
	 
}
